package com.starsoft.smdc.crawler.eastmoney;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.fasterxml.jackson.databind.JsonNode;
import com.starsoft.frame.fileimport.JsonReader;
import com.starsoft.frame.fileimport.pojo.Column;
import com.starsoft.frame.fileimport.pojo.DataTable;
import com.starsoft.frame.fileimport.pojo.NullType;
import com.starsoft.frame.fileimport.pojo.Table;
import com.starsoft.frame.fileimport.pojo.Table.TitleType;
import com.starsoft.frame.fileimport.pojo.ValueType;
import com.starsoft.frame.util.DateUtil;
import com.starsoft.frame.util.MapUtil;
import com.starsoft.smdc.bean.SmdcFundNavPre;
import com.starsoft.smdc.bean.SmdcFundNavPre.SmdcFundNavPreSystem;
import com.starsoft.smdc.bean.SmdcSecurity;
import com.starsoft.smdc.crawler.common.CrawlerService;
import com.starsoft.smdc.crawler.common.FundNavPreCrawler;
import com.starsoft.smdc.dao.FundNavPreDao;
import com.starsoft.smdc.service.SecurityService;
import com.starsoft.smdc.util.SecurityType;

public class FundNavPreEastmoney extends CrawlerService implements FundNavPreCrawler{

	private static Logger logger = LoggerFactory.getLogger(FundNavPreEastmoney.class);
	
	private final String EASTMONEY="eastmoney";
	
	private Map<String, SmdcFundNavPre> navCache = new HashMap<>();
	// 缓存有效时间5mins
	private int validateTime = 1000*60*5;
	
	@Autowired
	private FundNavPreDao preDao;
	
	@Autowired
	private SecurityService securityService;
	
	@Override
	public SmdcFundNavPre get(SmdcSecurity security){
		return get(Arrays.asList(security)).get(security.getSecId());
	}
	
	@Override
	public Map<String, SmdcFundNavPre> get(List<SmdcSecurity> securities) {
		Map<String, SmdcFundNavPre> result = new HashMap<>();
		StringBuilder secIds = new StringBuilder();
		for (SmdcSecurity sec : securities) {
			if (!SecurityType.isFund(sec.getSecType())) {
				continue;
			}
			SmdcFundNavPre navPre = getFromCache(sec);
			if (navPre != null) {
				result.put(sec.getSecId(), navPre);
			} else {
				secIds.append(",").append(convertSecId(sec.getSecId(), false));
			}
		}
		if(secIds.length()<1){
			return result;
		}
		String apiName = "fundNavPre";
		String t = String.valueOf(System.currentTimeMillis());
		String response = request(apiName, secIds.substring(1), t);
		JsonNode preListNode = getJsonNode(response).get("Datas");
		
		List<Column> columnList = new ArrayList<Column>();
		columnList.add(new Column("fundcode", "secId", ValueType.String, NullType.nullable));
		columnList.add(new Column("gsz", "preNav", ValueType.Double, NullType.nullable));
		columnList.add(new Column("gztime", "preDate", ValueType.Date, NullType.nullable, "yyyy-MM-dd HH:mm"));
		Table table = new Table(TitleType.OnlyCode, columnList);
		
		JsonReader reader = new JsonReader();
		DataTable dataTable = reader.read(preListNode.toString(), table);
		for (Map<String, Object> mapObject : dataTable.getData()) {
			SmdcFundNavPre navPre = MapUtil.toBean(SmdcFundNavPre.class, mapObject);
			navPre.setSecId(convertSecId(navPre.getSecId(), true));
			navPre.setPreSystem(SmdcFundNavPreSystem.easyMoney);
			result.put(navPre.getSecId(), navPre);
		}
		navCache.putAll(result);
		return result;
	}
	
	private SmdcFundNavPre getFromCache(SmdcSecurity security){
		long now = new Date().getTime();
		SmdcFundNavPre navPre = navCache.get(security.getSecId());
		
		if(navPre == null || navPre.getPreDate() == null) {
			return null;
		}
		
		if (DateUtil.isToday(navPre.getPreDate())) {
			if (!holidayService.isBeforeClose(navPre.getPreDate())) {
				return navPre;
			} else if (now - navPre.getPreDate().getTime() < validateTime) {
				return navPre;
			}
		}
		return null;
	}
	
	@Override
	protected String getTargetSystem() {
		return EASTMONEY;
	}

	@Override
	protected String convertSecId(String secId, boolean isToLocal) {
		if (isToLocal) {
			List<SmdcSecurity> secs = securityDao.getByTicker(secId);
			if(secs.size()==0){
				throw new RuntimeException("Not find "+secId+" in DB");
			} else if(secs.size()>1){
				for(SmdcSecurity sec:secs ){
					if(!SecurityType.isIndex(sec.getSecType())){
						return sec.getSecId();
					}
				}
				throw new RuntimeException("Not find "+secId+" in DB");
			} else {
				return secs.get(0).getSecId();
			}
		} else {
			return secId.split("\\.")[0];
		}
	}

	public String update() {
		List<SmdcSecurity> securityList = securityService.getAll();
		List<SmdcSecurity> securitys = new ArrayList<>();
		Date now = new Date();
		for (SmdcSecurity security : securityList) {
			if(!securityService.isDlist(security, now)){
				securitys.add(security);
			}
		}
		Date preDate = holidayService.getBusinessDay(now, true);
		
		List<SmdcFundNavPre> result = new ArrayList<>();
		Map<String, SmdcFundNavPre> navMap = get(securitys);
		for(SmdcFundNavPre nav : navMap.values()){
			if(nav.getPreDate()==null){
				nav.setPreDate(preDate);
			}
			SmdcFundNavPre navDb = preDao.getPre(nav.getSecId(), nav.getPreDate());
			if(navDb!=null){
				navDb.setPreNav(nav.getPreNav());
				navDb.setPreSystem(nav.getPreSystem());
				preDao.update(navDb);
				result.add(navDb);
			} else {
				preDao.save(nav);
				result.add(nav);
			}
		}
		return "update "+result.size();
	}

	public Map<String, SmdcFundNavPre> getFundPreNavOnTime(List<SmdcSecurity> securities, Date tradeDate){
		Map<String, SmdcFundNavPre> result = new HashMap<>();
		if (DateUtil.isToday(tradeDate) && holidayService.isBeforeClose(new Date())) {
			result = this.get(securities);
		} else {
			for(SmdcSecurity sec: securities){
				SmdcFundNavPre market = preDao.getPre(sec.getSecId(), tradeDate);
				if(market !=null){
					result.put(sec.getSecId(), market);
				}
			}
		}
		return result;
	}
	
}
